package day08;

import day04.handler.FirstClientHandler;
import day08.handler.ClientHandler;
import day08.handler.inBoundHandler.InBoundHandlerA;
import day08.packet.MessageRequestPacket;
import day08.util.LoginUtil;
import day08.util.PacketCodeC;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;

import java.util.Date;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;

/**
 * @author chenshijie
 * @date 2023/12/23 16:24
 */

public class NettyClient {

    static int MAX_RETRY = 2;

    private static final String HOST = "127.0.0.1";

    private static final int port = 8001;

    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();

        NioEventLoopGroup group = new NioEventLoopGroup();

        bootstrap
                .group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
//                        ch.pipeline().addLast(new FirstClientHandler());
                        ch.pipeline().addLast(new ClientHandler());
                    }
                });
//                .handler(new ClientHandler());

        connect(bootstrap, HOST, port, MAX_RETRY);
    }

    private static void connect(Bootstrap bootstrap, String host, int port, int retry){
        GenericFutureListener<Future<? super Void>> futureListener = new GenericFutureListener<Future<? super Void>>() {
            @Override
            public void operationComplete(Future<? super Void> future) throws Exception {
                if (future.isSuccess()) {
                    System.out.println("连接成功！");
                    Channel channel = ((ChannelFuture) future).channel();
                    startConsoleThread(channel);

                } else if (retry == 0) {
                    System.err.println("重试次数过多，放弃连接！");
                    bootstrap.config().group().shutdownGracefully();


                } else {
                    int order = (MAX_RETRY - retry) + 1;
                    // 重连间隔
                    int delay = 1 << order;
                    System.err.println(new Date() + "：连接失败，第" + order + "次重连......");

                    bootstrap.config().group().schedule(() -> connect(bootstrap, host, port, retry - 1), delay, TimeUnit.SECONDS);

                }
            }
        };


        ChannelFuture channelFuture = bootstrap
                .connect(host, port)
                .addListener(futureListener);

    }

    private static void startConsoleThread(Channel channel) {
        new Thread(() -> {
            while (!Thread.interrupted()) {
                if (LoginUtil.hasLogin(channel)) {
                    System.out.println("输入消息发送至服务端: ");
                    Scanner sc = new Scanner(System.in);
                    String line = sc.nextLine();
                    sendMsg(channel, line);
                }
            }
        }).start();
    }

    private static void sendMsg(Channel channel, String msg) {
        MessageRequestPacket packet = new MessageRequestPacket();
        packet.setMessage(msg);
        ByteBuf byteBuf = PacketCodeC.INSTANCE.encode(channel.alloc(), packet);
        channel.writeAndFlush(byteBuf);
    }
}
